/**
 * Copyright (c) 2019, ShangHai YTO Co., Ltd.
 * All right reserved.
 *
 * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF YTO
 * CO., LTD.  THE CONTENTS OF THIS FILE MAY NOT BE DISCLOSED
 * TO THIRD PARTIES, COPIED OR DUPLICATED IN ANY FORM, IN WHOLE OR IN PART,
 * WITHOUT THE PRIOR WRITTEN PERMISSION OF YTO
 * CO., LTD.
 */
package org.sc.xl;

import com.alibaba.fastjson.JSONArray;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpHeaders;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.FileEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultRedirectStrategy;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.stream.Stream;

/**
 * @description: TODO 请在此添加描述
 * @reason: TODO ADD REASON(可选)
 * @author FXL
 *
 * @date 2023/8/8 11:05 
 * @since JDK 1.8
 */
public class DorisStreamLoader {


    private final static String HOST = "10.130.253.66";
    private final static int PORT = 18040;
    private final static String DATABASE = "ytrpt";   // 要导入的数据库
    private final static String TABLE = "app_realtime_order_customer";     // 要导入的表
    private final static String USER = "root";      // Doris 用户名
    private final static String PASSWD = "";        // Doris 密码
    private final static String LOAD_FILE_NAME = "C://Users/admin/Desktop/t_app_major_market_d.xls_0.csv"; // 要导入的本地文件路径

    private final static String loadUrl = String.format("http://%s:%s/api/%s/%s/_stream_load",
            HOST, PORT, DATABASE, TABLE);

    private final static HttpClientBuilder httpClientBuilder = HttpClients
            .custom()
            .setRedirectStrategy(new DefaultRedirectStrategy() {
                @Override
                protected boolean isRedirectable(String method) {
                    // 如果连接目标是 FE，则需要处理 307 redirect。
                    return true;
                }
            });

    public void load(File file) throws Exception {
        try (CloseableHttpClient client = httpClientBuilder.build()) {
            HttpPut put = new HttpPut(loadUrl);
            put.setHeader(HttpHeaders.EXPECT, "100-continue");
            put.setHeader(HttpHeaders.AUTHORIZATION, basicAuthHeader(USER, PASSWD));

            // 可以在 Header 中设置 stream load 相关属性，这里我们设置 label 和 column_separator。
            put.setHeader("label", UUID.randomUUID().toString());
            put.setHeader("column_separator", ",");
            put.setHeader("max_filter_ratio", "0.2");
            // 设置导入文件。
            // 这里也可以使用 StringEntity 来传输任意数据。
            FileEntity entity = new FileEntity(file);
            put.setEntity(entity);

            try (CloseableHttpResponse response = client.execute(put)) {
                String loadResult = "";
                if (response.getEntity() != null) {
                    loadResult = EntityUtils.toString(response.getEntity());
                }

                final int statusCode = response.getStatusLine().getStatusCode();
                if (statusCode != 200) {
                    throw new IOException(
                            String.format("Stream load failed. status: %s load result: %s", statusCode, loadResult));
                }

                System.out.println("Get load result: " + loadResult);
            }
        }
    }

    /**
     * JSON格式的数据导入
     * @param jsonData
     * @throws Exception
     */
    public void loadJson(String jsonData) throws Exception {
        try (CloseableHttpClient client = httpClientBuilder.build()) {
            HttpPut put = new HttpPut(loadUrl);
            put.removeHeaders(HttpHeaders.CONTENT_LENGTH);
            put.removeHeaders(HttpHeaders.TRANSFER_ENCODING);
            put.setHeader(HttpHeaders.EXPECT, "100-continue");
            put.setHeader(HttpHeaders.AUTHORIZATION, basicAuthHeader(USER, PASSWD));
            // You can set stream load related properties in the Header, here we set label and column_separator.
            put.setHeader("label", UUID.randomUUID().toString());
            put.setHeader("column_separator", ",");
            put.setHeader("format", "json");
            put.setHeader("strip_outer_array", "true");
            // Set up the import file. Here you can also use StringEntity to transfer arbitrary data.
            StringEntity entity = new StringEntity(jsonData, "utf-8");
            put.setEntity(entity);
            try (CloseableHttpResponse response = client.execute(put)) {
                String loadResult = "";
                if (response.getEntity() != null) {
                    loadResult = EntityUtils.toString(response.getEntity());
                }
                final int statusCode = response.getStatusLine().getStatusCode();
                if (statusCode != 200) {
                    throw new IOException(String.format("Stream load failed. status: %s load result: %s", statusCode, loadResult));
                }
                System.out.println("Get load result: " + loadResult);
            }
        }
    }

    private String basicAuthHeader(String username, String password) {
        final String tobeEncode = username + ":" + password;
        byte[] encoded = Base64.encodeBase64(tobeEncode.getBytes(StandardCharsets.UTF_8));
        return "Basic " + new String(encoded);
    }


    private static class Task implements Callable<String> {

        private Map<String , String> stringStringMap;

        private DorisStreamLoader loader;


        public Task(Map<String , String> stringStringMap , DorisStreamLoader loader){
            this.stringStringMap = stringStringMap;
            this.loader = loader;
        }

        @Override
        public String call() throws Exception {
            List<CustomerVO> resultList = Lists.newArrayList();
            stringStringMap.forEach((k, v) -> {
                String[] keys = k.split(";");
                CustomerVO customerVO = CustomerVO.builder()
                        .rpt_date("2023-09-20 10:20:00")
                        .org_code(keys[0])
                        .org_name(keys[1])
                        .sub_code(keys[2])
                        .amount(new Long(v))
                        .build();
                resultList.add(customerVO);
                if (resultList.size() % 1000 == 0) {
                    try {
                        loader.loadJson(JSONArray.toJSONString(resultList));
                        resultList.clear();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });
            return null;
        }
    }

    public static void main(String[] args) throws Exception {
        DorisStreamLoader loader = new DorisStreamLoader();
//        JedisCluster jedisCluster = getJedisCluster();
//        ExecutorService executor = Executors.newFixedThreadPool(10);
//        List<Future<String>> futureList = Lists.newArrayList();
//        long current = System.currentTimeMillis();
//        Stream.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9).forEach(e -> {
//            Future<String> future = executor.submit(new Task(jedisCluster.hgetAll("_order_customer_" + e), loader));
//            futureList.add(future);
//        });
//        long end = System.currentTimeMillis();
//        System.err.println("耗时:" + (end - current) / 1000l);
        loader.load(new File(LOAD_FILE_NAME));
    }


    private static JedisCluster getJedisCluster() {
        Set<HostAndPort> hostAndPortSet = Sets.newHashSet(
                new HostAndPort("10.130.36.243", 6387), new HostAndPort("10.130.36.243", 6388), new HostAndPort("10.130.36.243", 6389),
                new HostAndPort("10.130.36.243", 6390), new HostAndPort("10.130.36.243", 6391), new HostAndPort("10.130.36.243", 6392)
        );
        JedisCluster jedisCluster = new JedisCluster(hostAndPortSet);
        return jedisCluster;

    }
}